﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using LitJson;
using System;
using SongeNS;
using NewEditorNS;
using FairyGUI.UI;
using System.Text;
using System.IO;
using VCity.Utils;
using CombinePicNS;
using ArtsWork;
using SimpleJSON;
using System.Linq;
using System.Windows.Forms;

public class ShopEditor
{
    bool _isLocalMode = true;
    //bool _isLocalMode = false;  //  原来的服务器模式
    public bool IsLocalMode { get { return _isLocalMode; } }

    public const string PreFix_RouteID = "zp";
    public static string LocalDataPath = UtilsHelper.GetDataPath() + "ShopData/";
    public const string FolderName_Sign = "sign/";
    public const string FileName_config = "config.txt";
    //public const string FileName_picName2Crc = "picName2Crc.txt";
    public const string FileName_shopList = "shopList.txt";
    public const string All_FileExtend_shopSignPic = ".jpg|.png";

    StringBuilder sb = new StringBuilder();
    public string GetRouteFolderPath(string routeID)
    {
        sb.Clear();
        sb.Append(LocalDataPath, routeID, "/");
        return sb.ToString();
    }
    public string GetShopConfigFilePath(string routeID)
    {
        sb.Clear();
        sb.Append(LocalDataPath, routeID, "/", FileName_config);
        return sb.ToString();
    }
    public string GetSignFolderPath(string routeID)
    {
        sb.Clear();
        sb.Append(LocalDataPath, routeID, "/", FolderName_Sign);
        return sb.ToString();
    }
    public string GetShopListFilePath(string routeID)
    {
        sb.Clear();
        sb.Append(LocalDataPath, routeID, "/", FileName_shopList);
        return sb.ToString();
    }

    #region 单例 与 初始化 

    static ShopEditor instance;
    public static ShopEditor Instance
    {
        get
        {
            if (instance == null)
                instance = new ShopEditor();
            return instance;
        }
    }

    ShopEditor()
    {
        string filePathHead = "file:///";
        string prefabPath = UnityEngine.Application.streamingAssetsPath + "/shop.assetbundle";
        LoadManager_WWW.instance.Load(filePathHead + prefabPath, www =>
        {
            initShopPrefab(www);
            //OnlyShopPrefab = OnlyShopPrefab == null ? Resources.Load("SongyiTest/ShopSignP/OnlyShopPrefab") as GameObject : OnlyShopPrefab;
            //OnlySignPrefab = OnlySignPrefab == null ? Resources.Load("SongyiTest/ShopSignP/OnlySignPrefab") as GameObject : OnlySignPrefab;
            OnlySignPrefab = MonoHelper.Instance.m_boardPrefab;
            OnlyShopPrefab = MonoHelper.Instance.m_shopPrefab;
        });

    }

    #endregion

    #region 数据
    /// <summary>左侧</summary>
    public List<ShopModelMono> theShopModelList = new List<ShopModelMono>();

    Dictionary<string, List<ShopModelMono>> allShopModelList = new Dictionary<string, List<ShopModelMono>>();

    Dictionary<string, List<ShopSignVO>> allBoardList = new Dictionary<string, List<ShopSignVO>>();

    /// <summary>底部</summary>
    public List<ShopSignVO> theShopSignList = new List<ShopSignVO>();
    /// <summary>右侧</summary>
    public List<ShopSignVO> theOriShopSignList = new List<ShopSignVO>();

    public Dictionary<string, Dictionary<string, string>> _dicRoute2PicNameCrc = new Dictionary<string, Dictionary<string, string>>();

    /// <summary>建筑-商铺列表</summary>
    Dictionary<string, List<ShopSignVO>> shopIdDic = new Dictionary<string, List<ShopSignVO>>();

    /// <summary>当前走向图ID</summary>
    public string CurRouteID;
    public bool IsUploadTemplate { get; set; }
    public void GetShopInfo(string fileStr, string routeID)
    {
        //string fileStr = File.ReadAllText(path);
        string enterStr = "\t\t\t\t\t\t\t\t\t\t\t\t";
        fileStr = fileStr.Replace(enterStr, "\r\n");

        string[] splitLine = new string[] { "\r\n" };
        string[] split = new string[] { "\t" };
        string[] lineArr = fileStr.Split(splitLine, System.StringSplitOptions.None);
        if (lineArr.Length < 1)
            Debug.Log("商铺数据格式不正确: " + fileStr);

        theOriShopSignList = new List<ShopSignVO>();
        for (int lineIndex = 1, lineNum = lineArr.Length; lineIndex < lineNum; lineIndex++)
        {
            string lineStr = lineArr[lineIndex];
            string[] dataArr = lineStr.Split(split, System.StringSplitOptions.None);
            ShopSignVO ss = new ShopSignVO();
            if (dataArr.Length > 4)
            {
                ss.SetSignCode(dataArr[0].Trim());

                //if (!SongeUtil.IsPic(ss.SignCode))
                //    ss.SignCode = ss.SignCode + ".jpg";
                ss.ShopName = dataArr[1].Trim();
                int.TryParse(dataArr[2].Trim(), out ss.CellNum);
                if (ss.CellNum <= 0)
                    ss.CellNum = 1;
                //ss.ShopCode = ShopSignEditor.instance.GetShopCodeByName(dataArr[3]);
                ss.ShopCode = MonoHelper.Instance.GetShopCodeByName(dataArr[3]);
                string prefabType = dataArr[4].Trim();
                if (prefabType == "只有铺面")
                    ss.PrefabType = ShopSignVO.PrefabTypeOnlyShop;
                else if (prefabType == "只有招牌")
                    ss.PrefabType = ShopSignVO.PrefabTypeOnlySign;
                else
                    ss.PrefabType = ShopSignVO.PrefabTypeShopSign;
                ss.RouteID = routeID;
            }
            if (ss.ShopName != "" && ss.ShopName != null)
                theOriShopSignList.Add(ss);

            for (int dataIndex = 0, dataNum = dataArr.Length; dataIndex < dataNum; dataIndex++)
            {
                string data = dataArr[dataIndex];
            }
        }

        //刷新列表
        //Dictionary<string, object> param = new Dictionary<string, object>();
        //param.Add("listName", UICONST.LIST_BOARD);
        //param.Add("dataList", theOriShopSignList);
        //EventManager.instance.DispatchEvent(null, UICONST.List_RefreshData, param);

    }

    void loadData(RoteAreaData raData, string routeID, bool isRoam = false)
    {
        //ShowBuildSign.instance.GetShopInfo(signFolderPath + shopDataListPath);

        ////记录build-ShopList字典 shopIdDic
        //if (!File.Exists(signFolderPath + saveTextName))
        //    return;
        //string saveStr = File.ReadAllText(signFolderPath + saveTextName);

        string saveStr = raData.StrConfig;
        var bytConfig = raData.byteConfig;

        theShopSignList.Clear();
        theShopModelList.Clear();

        JDataShopConfig shopConfig;
        shopConfig = JDataShopConfig.LoadFromString(saveStr);
        if (!shopConfig.IsValid(routeID, true))
        {
            shopConfig = JDataShopConfig.LoadFromString(UtilsCommonS.Byte2StringDefault(bytConfig));
        }

        if (shopConfig.version != null)
        {
            Debug.Log("存档版本号: " + shopConfig.version);
        }

        if (!isRoam)
        {
            if (!string.IsNullOrEmpty(shopConfig.routeID))
            {
                if (shopConfig._dicPicName2Crc != null)
                {
                    _dicRoute2PicNameCrc.AddOrReplace(shopConfig.routeID, shopConfig._dicPicName2Crc);
                }
            }
        }

        HashSet<string> hSetUIDs = null;
        if (isRoam)
        {
            hSetUIDs = _dicRoamRouteID2BuildUID.ForceGetValueOrDefault(shopConfig.routeID);
        }
        JsonData dataJD = shopConfig.data;
        if (dataJD != null)
        {
            for (int i = 0, length = dataJD.Count; i < length; i++)
            {
                JsonData shopJD = dataJD[i];

                ShopModelMono smm = createShopContainerWorld(shopJD["pointList"].ToVec3List(), shopJD["buildName"].ToString());

                smm.ReadJsonData(shopJD);
                // set shopconfig routeid (老数据需要)
                if (!UtilsCommonS.IsStringNullOrEmptyOrDefault(shopConfig.routeID))
                {
                    smm.SetSignRouteID(shopConfig.routeID);
                }

                if (isRoam)
                {
                    _dicBuildUID2ShopModel.AddToList(smm.BuildingName, smm);
                    if (hSetUIDs != null)
                    {
                        hSetUIDs.Add(smm.BuildingName);
                    }

                    //smm.CreateShops();
                }
                else
                {
                    for (int shopIndex = 0, shopCount = smm.ShopSignList.Count; shopIndex < shopCount; shopIndex++)
                    {
                        shopIdDic.AddToList(smm.BuildingName, smm.ShopSignList[shopIndex]);
                    }

                    smm.CreateShops();
                    theShopModelList.Add(smm);
                }
            }
        }
    }

    public void ClearScene()
    {
        for (int i = 0, length = theShopModelList.Count; i < length; i++)
        {
            GameObject.Destroy(theShopModelList[i].gameObject);
        }
        theShopModelList.Clear();
    }

    #endregion

    #region 选中

    ShopModelMono _curSelectShopModel;
    /// <summary>当前店铺面片</summary>
    public ShopModelMono CurSelectShopModel
    {
        get { return _curSelectShopModel; }
        set
        {
            curSelectedShopSign = null;
            ShopModelMono oldModel = _curSelectShopModel;
            if (oldModel != null)
                oldModel.IsSelect = false;
            _curSelectShopModel = value;

            if (_curSelectShopModel != null)
            {
                _curSelectShopModel.IsSelect = true;
                _curSelectShopModel.CreateShops();
                if (_curSelectShopModel.ShopSignList != null)
                {
                    theShopSignList.Clear();
                    theShopSignList.AddRange(_curSelectShopModel.ShopSignList);
                    //刷新列表UI
                    EventManager.instance.DispatchEvent(null, UICONST.List_RefreshData,
                        new SEvent<string, object>(UICONST.LIST_COMBINED, theShopSignList));

                }
                else
                {
                    theShopSignList.Clear();
                    //刷新列表UI
                    EventManager.instance.DispatchEvent(null, UICONST.List_RefreshData,
                        new SEvent<string, object>(UICONST.LIST_COMBINED, theShopSignList));
                }
            }
            Vector3 cameraPos = _curSelectShopModel.worldCenter + _curSelectShopModel.worldNormal.GetScaledVector(10f);
            cameraPos = new Vector3(cameraPos.x, 0, cameraPos.z);
            SceneManager.Instance.TheCameraCtrl.TheFocusCtrl.FocusPos = cameraPos;
            SceneManager.Instance.TheCameraCtrl.TheFocusCtrl.RotH = SongeUtil.GetRotateY(_curSelectShopModel.worldNormal) + 90f;
            //PicViewMono.instance.ShowBuildingPic(_curSelectShopModel.BuildingName, NewEditor.instance.curFolderPath + "pic/");//CHECK
        }
    }

    ShopSignVO curSelectedShopSign;

    #endregion

    #region 打点
    List<Vector3> pointList;
    GameObject ball1;
    GameObject ball2;
    GameObject ball3;
    void initBall()
    {
        if (ball1 == null)
        {
            Vector3 ballScale = new Vector3(0.3f, 0.3f, 0.3f);
            ball1 = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            ball1.transform.localScale = ballScale;
            ball1.name = "ball1";
            ball1.SetActive(false);
            ball2 = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            ball2.transform.localScale = ballScale;
            ball2.SetActive(false);
            ball2.name = "ball2";
            ball3 = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            ball3.transform.localScale = ballScale;
            ball3.SetActive(false);
            ball3.name = "ball3";
        }
    }
    public void onClickPoint(string buildGUID, Vector3 worldVec)
    {
        initBall();
        if (pointList == null)
        {
            pointList = new List<Vector3>();
        }
        pointList.Add(worldVec);
        switch (pointList.Count)
        {
            case 1:
                ball1.SetActive(true);
                ball1.transform.position = worldVec;
                break;
            case 2:
                ball2.SetActive(true);
                ball2.transform.position = worldVec;
                break;
            case 3:
                ball3.SetActive(true);
                ball3.transform.position = worldVec;
                break;
            default:
                break;
        }

        if (pointList.Count == 4)
        {
            Debug.Log("创建框体");
            ShopModelMono smm = createShopContainerWorld(pointList, buildGUID);
            AddShopSignEditorVo(smm, "signFile");
            theShopModelList.Add(smm);
            ball1.SetActive(false);
            ball2.SetActive(false);
            ball3.SetActive(false);
            CurSelectShopModel = smm;
            pointList = null;

            EventManager.instance.DispatchEvent(null, UICONST.List_RefreshData,
                new SEvent<string, object>(UICONST.LIST_SHOP, theShopModelList));

        }
    }

    /// <summary>
    /// Cancel Point
    /// </summary>
    public void CancelClickPoint()
    {
        pointList = null;
        //UILabel stepLabel = GameObject.Find("Step2").GetComponent<UILabel>();
        //stepLabel.text = step2Text + "[选择左下角点]";
        ball1.SetActive(false);
        ball2.SetActive(false);
        ball3.SetActive(false);
        //CurStep = 2;
    }

    /// <summary>
    /// Undo Point
    /// </summary>
    public void UndoClickPoint()
    {
        initBall();
        if (pointList == null)
        {
            pointList = new List<Vector3>();
        }
        // UILabel stepLabel = GameObject.Find("Step2").GetComponent<UILabel>();
        switch (pointList.Count)
        {
            case 1:
                ball1.SetActive(false);
                //stepLabel.text = step2Text + "[选择左上角点]";
                pointList.RemoveAt(0);
                break;
            case 2:
                ball2.SetActive(false);
                //stepLabel.text = step2Text + "[选择左上角点]";
                pointList.RemoveAt(1);
                break;
            case 3:
                ball3.SetActive(false);
                // stepLabel.text = step2Text + "[选择右上角点]";
                pointList.RemoveAt(2);
                break;
            default:
                break;
        }
    }

    #endregion

    #region 模型创建


    WWW shopWWW;
    Dictionary<string, GameObject> shopPrefabDic;
    public GameObject OnlyShopPrefab;
    public GameObject OnlySignPrefab;
    Dictionary<int, string> cellNameDic;
    public float CellWidth;

    void initShopPrefab(WWW www)
    {
        shopWWW = www;
        CellWidth = 3.8f;//预制件宽度

        shopPrefabDic = new Dictionary<string, GameObject>();
        GameObject all = shopWWW.assetBundle.mainAsset as GameObject;
        for (int i = 0, length = all.transform.childCount; i < length; i++)
        {
            GameObject child = all.transform.GetChild(i).gameObject;
            shopPrefabDic.AddRep(child.name, child);
        }
        cellNameDic = new Dictionary<int, string>();
        cellNameDic.Add(1, "sp_aa");
        cellNameDic.Add(2, "sp_ab");
        cellNameDic.Add(3, "sp_ac");
        cellNameDic.Add(4, "sp_ad");
        cellNameDic.Add(5, "sp_ae");
        cellNameDic.Add(6, "sp_af");
        cellNameDic.Add(7, "sp_ag");
        for (int i = 8; i < 50; i++)
        {
            cellNameDic.AddRep(i, "sp_ag");
        }

    }

    public GameObject CreateShopModel(int cellNum, string prefabType = "ShopSign")
    {
        switch (prefabType)
        {
            case "ShopSign":
                string index = cellNameDic[cellNum];

                GameObject shopSignGO = GameObject.Instantiate(shopPrefabDic[index]);

                SongeUtil.forAllChildren(shopSignGO, go =>
                {
                    Renderer r = go.GetComponent<Renderer>();
                    if (r != null)
                    {
                        for (int i = 0, len = r.materials.Length; i < len; i++)
                        {
                            r.materials[i].shader = Shader.Find("Legacy Shaders/Diffuse");
                        }
                    }
                });

                //SongeUtil.ChangeShader(shopSignGO);
                return shopSignGO;
            case "OnlyShop":

                GameObject shop = GameObject.Instantiate(OnlyShopPrefab);
                //SongeUtil.forAllChildren(shop, go =>
                //{
                //    Renderer r = go.GetComponent<Renderer>();
                //    if (r != null)
                //    {
                //        for (int i = 0, len = r.materials.Length; i < len; i++)
                //        {
                //            r.materials[i].shader = Shader.Find("Legacy Shaders/Diffuse");
                //        }
                //    }
                //});
                //SongeUtil.ChangeShader(shop);
                Vector3 oldShopScale = shop.transform.localScale;
                shop.transform.GetChild(0).localScale = new Vector3(3.8f * cellNum, 3.5f, 1);
                shop.transform.GetChild(0).localPosition = new Vector3(-1.9f * cellNum, 0, 1.75f);
                return shop;
            case "OnlySign":

                GameObject sign = GameObject.Instantiate(OnlySignPrefab);
                //SongeUtil.forAllChildren(sign, go =>
                //{
                //    Renderer r = go.GetComponent<Renderer>();
                //    if (r != null)
                //    {
                //        for (int i = 0, len = r.materials.Length; i < len; i++)
                //        {
                //            r.materials[i].shader = Shader.Find("Legacy Shaders/Diffuse");
                //        }
                //    }
                //});
                //SongeUtil.ChangeShader(sign);
                Vector3 oldsignScale = sign.transform.localScale;
                sign.transform.GetChild(0).localScale = new Vector3(3.8f * cellNum, 3.5f, 1);
                sign.transform.GetChild(0).localPosition = new Vector3(-1.9f * cellNum, 0, 1.75f);
                return sign;
            default:
                return shopPrefabDic[cellNameDic[cellNum]];
        }
    }

    public static ShopModelMono createShopContainerWorld(List<Vector3> pointList, string buildGUID)
    {
        //MeshFilter mf = Model.GetComponentInChildren<MeshFilter>();
        GameObject shopContainer = new GameObject();
        shopContainer.name = "shopModel";
        ShopModelMono shopModel = shopContainer.AddComponent<ShopModelMono>();
        shopModel.CellWidth = 3.8f;//TODO songyi 从配置读取
        shopModel.BuildingName = buildGUID;
        shopModel.CreatePlane(pointList);
        return shopModel;
    }



    #endregion

    #region 撤销

    List<ShopSignEditorVo> shopSignEditorVo = new List<ShopSignEditorVo>();
    public void Undo()
    {
        if (shopSignEditorVo.Count <= 0)
        {
            Debug.Log("不能撤消");
            return;
        }
        Debug.Log("撤消");
        ShopSignEditorVo shopVo = shopSignEditorVo[shopSignEditorVo.Count - 1];
        if (shopVo.undo == null)
        {
            Debug.Log(shopVo.undo.ToString());
        }
        List<ShopSignVO> ShopSignList = null;
        List<Vector3> pointList = null;
        string buildName = null;
        List<ShopModelMono> saveList = theShopModelList;//.dataProvider.ConvertAll<ShopModelMono>(data => { return data as ShopModelMono; });

        if (shopVo.type == null)
        {
            ShopSignList = shopVo.undo["shopSignList"].ToItemVOList<ShopSignVO>();
            pointList = shopVo.undo["pointList"].ToVec3List();
            buildName = shopVo.undo["buildName"].ToString();
            theShopSignList.Clear();// theShopSignList.dataProvider.Clear();
            if (buildName == CurSelectShopModel.BuildingName)
            {
                for (int shopIndex = 0, shopCount = ShopSignList.Count; shopIndex < shopCount; shopIndex++)
                {
                    shopIdDic.AddToList(buildName, ShopSignList[shopIndex]);
                }
                theShopSignList.AddRange(ShopSignList);
            }
            else
            {
                for (int i = 0, length = saveList.Count; i < length; i++)
                {
                    if (saveList[i] == shopVo.shopModel)
                    {
                        saveList[i].ShopSignList = ShopSignList;
                    }
                }
                CurSelectShopModel = shopVo.shopModel;
            }
        }
        else
        {
            if (shopVo.shopModel == null)
            {
                ShopSignList = shopVo.undo["shopSignList"].ToItemVOList<ShopSignVO>();
                pointList = shopVo.undo["pointList"].ToVec3List();
                buildName = shopVo.undo["buildName"].ToString();
                theShopSignList.Clear();
                shopVo.shopModel = createShopContainerWorld(pointList, buildName);
                theShopModelList.Add(shopVo.shopModel);
                shopVo.shopModel.ShopSignList = ShopSignList;
                CurSelectShopModel = shopVo.shopModel;
            }
            else
            {
                theShopModelList.Remove(shopVo.shopModel);
            }

        }
        shopSignEditorVo.Remove(shopVo);
        //onDataChange();
        // 刷新UI
        EventManager.instance.DispatchEvent(null, UICONST.List_RefreshData,
new SEvent<string, object>(UICONST.LIST_SHOP, theShopModelList));
    }

    void AddShopSignEditorVo(ShopModelMono _mono, string _type = null)
    {

        ShopSignEditorVo vo = new ShopSignEditorVo();
        if (_mono != null)
        {
            vo.undo = _mono.ToJsonData();
            vo.type = _type;
            vo.shopModel = _mono;
        }
        shopSignEditorVo.Add(vo);
    }

    class ShopSignEditorVo
    {
        public JsonData undo;
        public JsonData redo;
        public string type;
        public ShopModelMono shopModel;
    }
    #endregion

    #region UI回调

    //CHECK 左侧ShopModelMono列表事件
    void onShopModelItemMessage(object data, string msg)//整排商铺项
    {
        ShopModelMono tar = data as ShopModelMono;
        switch (msg)
        {
            case "onClick":
                CurSelectShopModel = tar;

                break;
            //case "onTestDelete":
            case UICONST.EventListItemDelete:
                AddShopSignEditorVo(tar, "signFile");
                theShopModelList.Remove(tar);
                if (tar == CurSelectShopModel)
                    theShopSignList.Clear();
                GameObject.Destroy(tar.gameObject);
                //刷新UI
                EventManager.instance.DispatchEvent(null, UICONST.List_RefreshData,
    new SEvent<string, object>(UICONST.LIST_SHOP, theShopModelList));
                //onDataChange();//刷新商铺模型
                break;
        }
    }

    //底部ShopSignVO列表事件
    void onShopSignItemMessage(object data, string msg)//商铺项
    {
        switch (msg)
        {
            case "onClick":
                ShopSignVO shopSign = data as ShopSignVO;
                curSelectedShopSign = shopSign;
                //SetSignFilter("_" + curSelectedShopSign.CellNum);
                break;
            case "onDelete":
                AddShopSignEditorVo(CurSelectShopModel);
                CurSelectShopModel.ShopSignList.Remove(data as ShopSignVO);
                theShopSignList.Clear();
                theShopSignList.AddRange(CurSelectShopModel.ShopSignList);
                //刷新商铺模型
                CurSelectShopModel.CreateShops();
                //刷新列表UI
                EventManager.instance.DispatchEvent(null, UICONST.List_RefreshData,
                    new SEvent<string, object>(UICONST.LIST_COMBINED, theShopSignList));
                break;
        }
    }

    //右侧ShopSignVO列表事件
    void onShopJsondataListItemMessage(object data, string msg)
    {
        ShopSignVO ss = new ShopSignVO();
        ss.ReadJsonData((data as ShopSignVO).ToJsonData());

        if (msg == "onClick" && CurSelectShopModel != null)
        {
            if (shopIdDic.ContainsKey(CurSelectShopModel.BuildingName))
                ss.ShopID = getNewShopID();
            else
                ss.ShopID = "0001";
            AddShopSignEditorVo(CurSelectShopModel);
            shopIdDic.AddToList(CurSelectShopModel.BuildingName, ss);
            CurSelectShopModel.ShopSignList.Add(ss);
            theShopSignList.Clear();
            theShopSignList.AddRange(CurSelectShopModel.ShopSignList);
            CurSelectShopModel.CreateShops();

            //刷新列表UI
            EventManager.instance.DispatchEvent(null, UICONST.List_RefreshData,
                new SEvent<string, object>(UICONST.LIST_COMBINED, theShopSignList));
        }
    }

    /// <summary>
    /// 只显示商铺、只显示招牌、显示商铺和招牌
    /// </summary>
    /// <param name="btnName"></param>
    public void onSelectShopPrefab(string btnName)
    {
        if (CurSelectShopModel != null)
        {
            for (int i = 0, length = CurSelectShopModel.ShopSignList.Count; i < length; i++)
            {
                ShopSignVO ssvo = CurSelectShopModel.ShopSignList[i];
                if (ssvo != null)
                {
                    switch (btnName)
                    {
                        case UICONST.BTN_SHOPANDBOARD:
                            ssvo.PrefabType = "ShopSign";
                            break;
                        case UICONST.BTN_SHOWSHOP:
                            ssvo.PrefabType = "OnlyShop";
                            break;
                        case UICONST.BTN_SHOWBOARD:
                            ssvo.PrefabType = "OnlySign";
                            break;
                    }
                    //Debug.Log("curSelectedShopSign.PrefabType: " + curSelectedShopSign.PrefabType);
                    Debug.Log("Show:  " + btnName);
                    if (ssvo.onDataChange != null)
                        ssvo.onDataChange();
                }
            }
            onDataChange();
        }
    }

    void onDataChange()
    {
        if (CurSelectShopModel != null)
        {
            CurSelectShopModel.CreateShops();
        }
    }

    /// <summary>获取新商铺ID(无重复)</summary>
    string getNewShopID()
    {
        int maxIndex = 1000;
        List<ShopSignVO> shopList = shopIdDic[CurSelectShopModel.BuildingName];
        bool[] indexArr = new bool[maxIndex];
        string res = null;
        for (int i = 0, length = shopList.Count; i < length; i++)
        {
            int tarIndex;
            if (int.TryParse(shopList[i].ShopID, out tarIndex))
            {
                if (tarIndex == Mathf.Clamp(tarIndex, 1f, maxIndex))
                {
                    indexArr[tarIndex] = true;
                }
            }
        }
        for (int i = 1; i <= maxIndex; i++)
        {
            if (!indexArr[i])
            {
                res = i.ToString("D4");
                break;
            }
        }
        return res;
    }

    #endregion

    public void OnMouseEvent(MouseEvent me)
    {
        if (MonoHelper.Instance.IsCruise)
        {
            return;
        }
        switch (me.eventType)
        {
            case MouseEvent.OnMouseClick:
                if (me.tar is SceneNodeMono)
                {
                    SceneNodeMono dac = me.tar as SceneNodeMono;
                    onClickPoint(dac.sceneNode.guid, me.worldPoint);
                }
                else if (me.tar is ShopModelMono)
                {
                    CurSelectShopModel = me.tar as ShopModelMono;
                }
                break;
        }
    }

    bool _isOnShopRouteDataGetFromLocal = false;
    IEnumerator Co_OnShopRouteDataGetFromLocal(string routeID, string folderPath = "", bool isSendNextMsg = true)
    {
        _isOnShopRouteDataGetFromLocal = true;
        var sb = UtilsCommonS.StrBuilder;
        sb.Clear();
        if (string.IsNullOrEmpty(folderPath))
        {
            sb.Append(ShopEditor.LocalDataPath, routeID, "/");
        }
        else
        {
            sb.Append(PathExtention.Combine(folderPath, routeID));
            sb.Append("/");
        }
        
        string localPath = sb.ToString();
        if (!UtilsCommonS.IsDirExists(localPath))
        {
            if (!MonoHelper.Instance.IsCruise)
            {
                new WindowAlertDialog("走向图" + routeID + "本地数据不存在!").ShowError();
            }
            else
            {
                Debug.Log("没有走向图" + routeID + "本地商铺数据(没有下载或者这块区域没有商铺)");
            }
            _isOnShopRouteDataGetFromLocal = false;
            yield break;
        }
        else
        {
            MonoHelper.Instance.InitWaiting("Waiting for SCD finishes downloading...");
            MonoHelper.Instance.AddWaiting();
            while (!MonoHelper.Instance.isSCDLoaded)
            {
                Debug.Log("Waiting for SCD finishes downloading...");
                yield return null;
            }

            MonoHelper.Instance.InitWaiting("RefreshShopDataFromLocal...");
            bool isSuccess = MonoHelper.Instance.RefreshShopDataFromLocal(routeID, localPath);
            if (isSuccess)
            {
                var shopModles = allShopModelList.TryGetReturnValue(routeID);
                if (shopModles != null)
                {
                    for (int i = 0; i < shopModles.Count; i++)
                    {
                        UnityEngine.Object.Destroy(shopModles[i].gameObject);
                    }
                    shopModles.Clear();
                }
                allShopModelList.Remove(routeID);

                allBoardList.Remove(routeID);

                if (isSendNextMsg)
                {
                    EventManager.instance.DispatchEvent(null, UICONST.SHOPROUTEDATAGET, routeID);
                }
            }
            else
            {
                new WindowAlertDialog("走向图" + routeID + "读取本地数据失败!").ShowError();
            }
        }

        MonoHelper.Instance.HideLoading();
        _isOnShopRouteDataGetFromLocal = false;
    }

    public void OnEvent(string eventName, object param)
    {
        switch (eventName)
        {
            case UICONST.ShopRouteDataGetFromLocal:
                {
                    if (!_isOnShopRouteDataGetFromLocal)
                    {
                        CoroutineProxy.Instance.StartCoroutine(Co_OnShopRouteDataGetFromLocal(param as string));
                    }
                }
                break;
            case UICONST.SHOPROUTEDATAGET:
                OnShopRouteDataGet(param as string);

                UserCache.SetRouteID(CurRouteID);
                // TODO:refresh UI
                //刷新列表UI

                // Left Shop List
                EventManager.instance.DispatchEvent(null, UICONST.List_RefreshData,
                    new SEvent<string, object>(UICONST.LIST_SHOP, theShopModelList));

                // Buttom Combined List
                EventManager.instance.DispatchEvent(null, UICONST.List_RefreshData,
                    new SEvent<string, object>(UICONST.LIST_COMBINED, theShopSignList));

                // Right Board List
                EventManager.instance.DispatchEvent(null, UICONST.List_RefreshData,
                    new SEvent<string, object>(UICONST.LIST_BOARD, theOriShopSignList));
                break;

            case UICONST.EventListItemSelect:
                Debug.Log("EventListItemSelect" + param);
                //通过param来获取目标列表
                SEvent<string, object> se = param as SEvent<string, object>;
                if (se != null)
                {
                    if (se.Param1 == UICONST.LIST_BOARD)
                        onShopJsondataListItemMessage(se.Param2 as ShopSignVO, "onClick");
                    else if (se.Param1 == UICONST.LIST_COMBINED)
                        onShopSignItemMessage(se.Param2 as ShopSignVO, "onClick");
                    else if (se.Param1 == UICONST.LIST_SHOP)
                        onShopModelItemMessage(se.Param2 as ShopModelMono, "onClick");
                }
                break;
            case UICONST.EventListItemDelete:
                SEvent<string, object> se2 = param as SEvent<string, object>;
                if (se2 != null)
                {
                    if (se2.Param1 == UICONST.LIST_COMBINED)
                        onShopSignItemMessage(se2.Param2 as ShopSignVO, "onDelete");
                    if (se2.Param1 == UICONST.LIST_SHOP)
                        onShopModelItemMessage(se2.Param2 as ShopModelMono, UICONST.EventListItemDelete);
                }
                break;

            case UICONST.EventBtnClick:
                switch (param.ToString())
                {
                    case UICONST.BTN_SAVE:
                        //上传到云端
                        CoroutineProxy.Instance.StartCoroutine(UploadToServer());
                        break;

                    case UICONST.BTN_CANCEL:
                        CancelClickPoint();
                        break;

                    case UICONST.BTN_UNDOPOINT:
                        UndoClickPoint();
                        break;
                    case UICONST.BTN_SHOWSHOP:
                        onSelectShopPrefab(UICONST.BTN_SHOWSHOP);
                        break;
                    case UICONST.BTN_SHOWBOARD:
                        onSelectShopPrefab(UICONST.BTN_SHOWBOARD);
                        break;
                    case UICONST.BTN_SHOPANDBOARD:
                        onSelectShopPrefab(UICONST.BTN_SHOPANDBOARD);
                        break;
                    case UICONST.BTN_UNDO:
                        Undo();
                        break;
                    case UICONST.BTN_SUBMIT:

                        break;

                    case UICONST.BTN_CREATEATLAS:
                        // 场景是否加载完成
                        if (!SceneManager.Instance.IsSceneLoaded())
                        {
                            WindowAlertDialog dlg = new WindowAlertDialog("场景尚未加载完成，不能保存到云端！");
                            dlg.Show();
                            return;
                        }

                        // 场景材质是否重建完成 
                        if (!MonoHelper.Instance.IsRebuildedMat)
                        {
                            WindowAlertDialog dlg = new WindowAlertDialog("材质重建过程中，不能保存到云端！");
                            dlg.Show();
                            return;
                        }


                        CoroutineProxy.Instance.StartCoroutine(UploadToServer(true, ()=>
                        {
                            //1.获取地块配置
                            JsonData areaJD = SceneManager.Instance.ToJsonData();

                            //2.生成图集
                            CombinePicUtil.Combine(areaJD, CurRouteID, LocalDataPath, () =>
                            {
                                //3.上传图集文件
                                //记录atlas的CRC并插入新的地块配置

                                string atlasFolderPath = LocalDataPath + "/" + CurRouteID + "/areaConfig/";
                                DirectoryInfo dirInfo = new DirectoryInfo(atlasFolderPath);
                                FileInfo[] fileInfoArr = dirInfo.GetFiles();
                                int leftToUpload = fileInfoArr.Length;

                                MonoHelper.Instance.InitWaiting("正在上传走向图" + CurRouteID + "的商铺图集图片");
                                MonoHelper.Instance.SetWaitingMax(leftToUpload);

                                for (int i = 0; i < fileInfoArr.Length; i++)
                                {
                                    FileInfo file = fileInfoArr[i];

                                    string fileType = "jpg";
                                    if (file.Name.EndsWith(".png"))
                                        fileType = "png";
                                    if (file.Name.EndsWith(".PNG"))
                                        fileType = "png";

                                    HttpService.UploadFile(file.Name, file.GetFileCrc(), file.GetFileBytes(), fileType,
                                        () =>
                                        {
                                            leftToUpload--;
                                            Debug.Log("上传图片完成: " + file.Name);
                                            MonoHelper.Instance.PopWaiting();
                                            if (leftToUpload == 0)
                                            {
                                                Debug.Log("全部图片上传完成!");

                                                //4.上传合并了商铺数据的地块配置
                                                //调用地块配置保存接口
                                                JsonData shopAreaJD = JsonUtils.ReadJsonFile(atlasFolderPath + "" + CurRouteID + ".txt");
                                                JSONNode jn = shopAreaJD.ToSimpleJsonNode();
                                                //Debug.Log(jn.ToString());
                                                CompEditor.Instance.SaveData(jn);
                                                MonoHelper.Instance.HideLoading();
                                            }
                                        },
                                        (errorType, msg) =>
                                        {
                                            Debug.LogError("上传图片失败: errorType: " + errorType.ToString() + ", msg: " + msg);
                                            MonoHelper.Instance.PopWaiting();
                                        });
                                }
                            });

                        }));
                        
                        break;
                    case UICONST.CHECKBOX_ISUPLOADTEMPLATE:
                        {
                            IsUploadTemplate = !IsUploadTemplate;
                        }
                        break;
                    case UICONST.BTN_SAVE2LOCAL:
                        {
                            SaveToLocal();
                        }
                        break;
                }
                break;
            case UICONST.BTN_UPDATESHOPALLCONFIG:
                {
                    CoroutineProxy.Instance.StartCoroutine(UpdateFromServer(param as string));
                }
                break;
        }
    }

    #region Roam MonoHelper.Instance.IsCruise
    enum RoamShopRouteState
    {
        NotInit = -1,
        NotLoaded = 0,
        Loading = 1,
        LoadSuccess = 2,
        LoadFailed = 3
    }
    Dictionary<string, RoamShopRouteState> _dicRoamRouteID2ShopState;
    Dictionary<string, HashSet<string>> _dicRoamRouteID2BuildUID;
    public Dictionary<string, HashSet<string>> DicRoamRouteID2BuildUID { get { return _dicRoamRouteID2BuildUID; } }
    Dictionary<string, List<ShopModelMono>> _dicBuildUID2ShopModel;
    public Dictionary<string, List<ShopModelMono>> DicBuildUID2ShopModel { get { return _dicBuildUID2ShopModel; } }

    public void ShowShopModels(string buildUID, bool isShow)
    {
        var listSmm = _dicBuildUID2ShopModel.TryGetReturnValue(buildUID);
        if (listSmm != null)
        {
            for (int i = 0; i < listSmm.Count; i++)
            {
                var item = listSmm[i];
                item.SetVisible(false);
            }
        }
    }

    void ShopInitRoam()
    {
        if (null == _dicRoamRouteID2ShopState)
        {
            _dicRoamRouteID2ShopState = new Dictionary<string, RoamShopRouteState>();
        }
        if (null == _dicRoamRouteID2BuildUID)
        {
            _dicRoamRouteID2BuildUID = new Dictionary<string, HashSet<string>>();
        }
        if (null == _dicBuildUID2ShopModel)
        {
            _dicBuildUID2ShopModel = new Dictionary<string, List<ShopModelMono>>();
        }
    }

    public void OnRoamLoadShops(string routeID)
    {
        ShopInitRoam();
        RoamShopRouteState state = _dicRoamRouteID2ShopState.TryGetReturnValue(routeID, RoamShopRouteState.NotInit);
        if (state != RoamShopRouteState.NotLoaded)
        {
            CoroutineProxy.Instance.StartCoroutine(RoamLoadShops(routeID));
        }
    }

    IEnumerator RoamLoadShops(string routeID)
    {
        RoamShopRouteState state = _dicRoamRouteID2ShopState.ForceGetValueOrDefault(routeID);
        if (state != RoamShopRouteState.NotLoaded)
        {
            yield break;
        }
        _dicRoamRouteID2ShopState[routeID] = RoamShopRouteState.Loading;

        yield return CoroutineProxy.Instance.StartCoroutine(Co_OnShopRouteDataGetFromLocal(routeID, null, false));
        RoteAreaData raData = MonoHelper.Instance.GetRouteDataById(ShopEditor.PreFix_RouteID + routeID);
        if (null == raData)
        {
            _dicRoamRouteID2ShopState[routeID] = RoamShopRouteState.LoadFailed;
            yield break;
        }

        loadData(raData, routeID, true);
        _dicRoamRouteID2ShopState[routeID] = RoamShopRouteState.LoadSuccess;
        Debug.Log(_dicRoamRouteID2ShopState[routeID]);
    }

    public void OnRoamUnLoadShops(string routeID)
    {
        RoamUnLoadShops(routeID);
    }

    public void RoamUnLoadShops(string routeID)
    {
        RoamShopRouteState state = _dicRoamRouteID2ShopState.TryGetReturnValue(routeID);
        Debug.Log(state + " " + _dicRoamRouteID2ShopState[routeID]);
        if (state != RoamShopRouteState.LoadSuccess)
        {
            return;
        }

        _dicRoamRouteID2ShopState.Remove(routeID);
        var ids = _dicRoamRouteID2BuildUID.TryGetReturnValue(routeID);
        var it = ids.GetEnumerator();
        while (it.MoveNext())
        {
            var item = it.Current;
            var listSmm = _dicBuildUID2ShopModel.TryGetReturnValue(item);
            if (listSmm != null)
            {
                for (int i = 0; i < listSmm.Count; i++)
                {
                    GameObject.Destroy(listSmm[i].gameObject);
                }
                listSmm.Clear();
            }
            _dicBuildUID2ShopModel.Remove(item);
        }
        _dicRoamRouteID2BuildUID.Remove(routeID);
    }

    public string GetRouteIDFromBlockName(string blkName)
    {
        if (MonoHelper.RouteIDNum > blkName.Length)
        {
            return string.Empty;
        }
        string routeID = blkName.Substring(0, MonoHelper.RouteIDNum);
        if (UtilsCommonS.IsIntNumber(routeID))
        {
            return routeID;
        }
        return string.Empty;
    }
    #endregion

    void OnShopRouteDataGet(string routID)
    {
        // songyi 160808 走向图切换后, 按走向图ID切换ShopModeMonoList 
        CurRouteID = routID;

        if (allShopModelList.TryGetValue(CurRouteID, out theShopModelList))
        {
            theShopModelList = allShopModelList[CurRouteID];

            allBoardList.TryGetValue(CurRouteID, out theOriShopSignList);
        }
        else
        {
            theShopModelList = new List<ShopModelMono>();
            allShopModelList.Add(CurRouteID, theShopModelList);

            RoteAreaData raData = MonoHelper.Instance.GetRouteDataById(ShopEditor.PreFix_RouteID + CurRouteID);
            if (null != raData)
            {
                // 解析右侧列表数据
                GetShopInfo(raData.StrShopList, CurRouteID);

                // 解析左侧列表数据
                loadData(raData, CurRouteID);

                // Cache Board List
                if (allBoardList.ContainsKey(CurRouteID))
                {
                    allBoardList.Remove(CurRouteID);
                }
                allBoardList.Add(CurRouteID, theOriShopSignList);
            }
        }

        theShopSignList.Clear();
    }

    bool _isUploading = false;
    IEnumerator UploadToServer(bool isForceUploadTemplate = false, Action finishCallback = null)
    {
        if (IsLocalMode)
        {
            if (_isUploading)
            {
                yield break;
            }
            _isUploading = true;
            int count = 0;
            foreach (var key in allShopModelList.Keys)
            {
                ++count;
                // todo hint
                bool localIsUploadTemplate = isForceUploadTemplate ? true : IsUploadTemplate;
                yield return CoroutineProxy.Instance.StartCoroutine(UploadDataOfOneRoute(key, localIsUploadTemplate));
            }

            _isUploading = false;
            if (finishCallback != null)
            {
                finishCallback();
            }
        }
        //else
        //{
        //    // origin 没有再维护
        //    foreach (var key in allShopModelList.Keys)
        //    {
        //        var data = allShopModelList[key];
        //        JDataShopConfig config = new JDataShopConfig();
        //        config.shopNum = data.Count.ToString();
        //        config.version = UtilsCommonS.Time2String();
        //        config.data = data.ToJsonDataList();

        //        //JsonData curData = new JsonData();
        //        //curData["data"] = data.ToJsonDataList();

        //        //JsonData saveJD = theShopModelList.ToJsonDataList();
        //        //string saveStr = JsonMapper.ToJson(saveJD);
        //        //saveStr = SongeUtil.Escape(saveStr);
        //        ResourceManager.Instance.UpdateRouteData(ShopEditor.PreFix_RouteID + key,
        //            config.ToJsonData().ToSimpleJsonNode().ToString(), () =>
        //            {
        //                new WindowAlertDialog("保存到云端成功!").Show();
        //            },
        //            (resp) =>
        //            {
        //                StringBuilder sb = new StringBuilder();
        //                sb.Append("保存到云端失败!\n");
        //                sb.Append(resp.Error);
        //                sb.AppendLine();
        //                sb.Append(resp.WwwText);
        //                new WindowAlertDialog(sb.ToString()).Show();
        //            }
        //            );
        //    }
        //}
    }

    void SaveToLocal()
    {
        int count = 0;
        foreach (var key in allShopModelList.Keys)
        {
            ++count;
            // todo hint
            SaveToLocalOfOneRoute(key);
            //yield return null;
        }
    }

    void SaveToLocalOfOneRoute(string routeID)
    {
        // shoplist运行时不会改, 不用存
        //RoteAreaData raData = MonoHelper.Instance.GetRouteDataById(ShopEditor.PreFix_RouteID + routeID);
        //var dic = raData.DicLocalName2FileInfo;
        //string infoStr = string.Empty;
        //if (isUploadTemplatePicFile)
        //{
        //    infoStr = raData.StrShopList;
        //}

        Dictionary<string, string> dicNameCrc = _dicRoute2PicNameCrc.TryGetReturnValue(routeID);
        if (null == dicNameCrc)
        {
            WindowAlertDialog.ShowNewDlg("保存到本地失败, 没有nameCrc表!", true);
            return;
        }

        // 只存config
        var data = allShopModelList[routeID];

        JDataShopConfig config = new JDataShopConfig();
        config.routeID = routeID;
        config.shopNum = data.Count.ToString();
        config.version = UtilsCommonS.Time2String();
        config.data = data.ToJsonDataList();
        config._dicPicName2Crc = dicNameCrc;

        var configStr = config.ToJsonData().ToSimpleJsonNode().ToString();

        string configFilePath = GetShopConfigFilePath(routeID);
        UtilsCommonS.Save2File(configFilePath, configStr);
    }

    #region  inner batchDownload
    public IEnumerator OnBatchDownload()
    {
        var list = MonoHelper.Instance.GetAllShopRouteIDs();
        for (int i = 0; i < list.Count; i++)
        {
            yield return CoroutineProxy.Instance.StartCoroutine(UpdateFromServer(list[i]));            
        }
        WindowAlertDialog.ShowNewDlg("批量下载完成!!");
    }
    #endregion
    #region inner batchUpload

    public void OnBatchUpload()
    {
        var dlg = new FolderBrowserDialog();
        dlg.RootFolder = Environment.SpecialFolder.MyComputer;
        dlg.SelectedPath = PathExtention.Combine(UnityEngine.Application.dataPath, "../ShopData");
        //dlg.SelectedPath = PathExtention.Combine(UnityEngine.Application.dataPath, "../ShopData", "test");
        if (dlg.ShowDialog() == DialogResult.OK)
        {
            CoroutineProxy.Instance.StartCoroutine(BatchUpload(dlg.SelectedPath));
        }
    }

    IEnumerator BatchUpload(string folderPath)
    {
        string routeID = string.Empty;
        var fSysInfos = DirectoryInfoExtention.GetDirFileSysInfos(folderPath);
        for (int i = 0; i < fSysInfos.Length; i++)
        {
            var item = fSysInfos[i];
            if (item.Attributes == FileAttributes.Directory)
            {
                yield return CoroutineProxy.Instance.StartCoroutine(LoadLocalAndUpload(folderPath, item.Name));
            }
        }
        WindowAlertDialog.ShowNewDlg("批量上传完成!!");
    }

    IEnumerator LoadLocalAndUpload(string folderPath, string routeID)
    {
        routeID = routeID.ToLower();
        if (routeID.StartsWith("zp"))
        {
            routeID = routeID.Remove(0, 2);
        }

        yield return CoroutineProxy.Instance.StartCoroutine(Co_OnShopRouteDataGetFromLocal(routeID, folderPath, false));
        OnShopRouteDataGet(routeID);

        yield return CoroutineProxy.Instance.StartCoroutine(UploadDataOfOneRoute(routeID, true));
    }
    #endregion

    WindowAlertDialog dlgHint = new WindowAlertDialog("");
    bool _isUploadDataOfOneRoute = false;
    IEnumerator UploadDataOfOneRoute(string routeID, bool isUploadTemplatePicFile)
    {
        if (_isUploadDataOfOneRoute)
        {
            Debug.LogError("isUploadDataOfOneRoute == true!");
        }
        _isUploadDataOfOneRoute = true;

        Dictionary<string, string> dicNameCrc = _dicRoute2PicNameCrc.TryGetReturnValue(routeID);
        if (null == dicNameCrc)
        {
            dicNameCrc = new Dictionary<string, string>();
            _dicRoute2PicNameCrc.Add(routeID, dicNameCrc);
        }
        else
        {
            // 重构map文件, 本地删除了没有了的图片服务器map表里也会删除(namecrc删了, 文件还在但是就找不到了)
            if (isUploadTemplatePicFile)
            {
                dicNameCrc.Clear();
            }
        }

        #region upload local files
        RoteAreaData raData = MonoHelper.Instance.GetRouteDataById(ShopEditor.PreFix_RouteID + routeID);
        if (null == raData)
        {
            Debug.LogError("读取本地配置失败 : " + routeID);
            _isUploadDataOfOneRoute = false;
            yield break;
        }
        var dic = raData.DicLocalName2FileInfo;

        string infoStr = string.Empty;
        if (isUploadTemplatePicFile)
        {
            infoStr = raData.StrShopList;
        }

        MonoHelper.Instance.InitWaiting("正在上传走向图" + routeID + "图片");
        MonoHelper.Instance.SetWaitingMax(dic.Count);
        var it = dic.GetEnumerator();
        while (it.MoveNext())
        {
            var item = it.Current;
            string name = item.Key;
            FileInfo fInfo = item.Value;
            byte[] fData = UtilsCommonS.LoadFile(fInfo);
            if (fData != null)
            {
                NameCrcData ncSign = new NameCrcData(name, fData);
                if (isUploadTemplatePicFile)
                {
                    ncSign.AsyncUploadData();
                    yield return ncSign.WaitForResult();
                    if (!ncSign.IsRequestSuccess)
                    {
                        WindowAlertDialog.ShowNewDlg("网络错误, 请重试 : " + ncSign.HttpResp_Error.WwwText, true);
                        MonoHelper.Instance.HideLoading();
                        _isUploadDataOfOneRoute = false;
                        yield break;
                    }
                    else
                    {
                        dicNameCrc.AddOrReplace(ncSign.Name, ncSign.Crc);
                    }
                    MonoHelper.Instance.PopWaiting();
                }
            }
            else
            {
                Debug.LogError("获取本地文件流失败 : " + fInfo.FullName);
            }
        }
        #endregion

        List<ShopSignVO> listTemplateSign = allBoardList.TryGetReturnValue(routeID);
        if (null == listTemplateSign || listTemplateSign.Count == 0)
        {
            var str = "走向图" + routeID + "中招牌模板未配置或读取出错";
            Debug.LogWarning(str);
            WindowAlertDialog.ShowNewDlg(str, true);
            _isUploadDataOfOneRoute = false;
            yield break;
        }

        // check template sign
        for (int i = 0; i < listTemplateSign.Count; i++)
        {
            ShopSignVO voSign = listTemplateSign[i];
            string signName = voSign.SignCode;
            //  没有配置图片的话直接编辑的时候就能看出来
            if (!string.IsNullOrEmpty(signName))
            {
                if (!dicNameCrc.ContainsKey(signName))
                {
                    dlgHint.ShowError();
                    dlgHint.SetInformation(routeID + "招牌模板配置表中项 " + signName + " 配置文件Map表中不存在!\n请检查shopList配置是否正确!\n如确定正确但未该图片未上传,请勾选\"是否上传招牌资源先上传一次!");
                }
            }
        }

        // update config
        var data = allShopModelList[routeID];
        for (int i = 0; i < data.Count; i++)
        {
            data[i].UpdateSignCrc(dicNameCrc);
        }

        JDataShopConfig config = new JDataShopConfig();
        config.routeID = routeID;
        config.shopNum = data.Count.ToString();
        config.version = UtilsCommonS.Time2String();
        config.data = data.ToJsonDataList();
        config._dicPicName2Crc = dicNameCrc;

        SaveToLocalOfOneRoute(routeID);

        MonoHelper.Instance.InitWaiting("正在上传走向图" + routeID + "配置");
        MonoHelper.Instance.AddWaiting();
        CoroutineProxy.Instance.StartCoroutine(ResourceManager.Instance.UploadRouteData(ShopEditor.PreFix_RouteID + routeID,
            config.ToJsonData().ToSimpleJsonNode().ToString(), infoStr, () =>
            {
                MonoHelper.Instance.HideLoading();
                _isUploadDataOfOneRoute = false;

                // 重新登录点击下载才能下载最新服务器数据
                new WindowAlertDialog(routeID + " 配置保存到云端成功!如要下载最新服务器走向图数据,需要重新登录!").Show();
            },
            (resp) =>
            {
                MonoHelper.Instance.HideLoading();
                _isUploadDataOfOneRoute = false;

                StringBuilder sb = new StringBuilder();
                sb.Append(routeID, "配置保存到云端失败!\n(再次保存试试)");
                if (resp != null)
                {
                    sb.Append(resp.Error);
                }
                sb.AppendLine();
                if (resp != null)
                {
                    sb.Append(resp.WwwText);
                }
                WindowAlertDialog.ShowNewDlg(sb.ToString(), true);
            }
            ));

        while (_isUploadDataOfOneRoute)
        {
            yield return null;
        }
    }

    bool _isDownloding = false;
    IEnumerator UpdateFromServer(string routeID2Update)
    {
        Debug.Log("Getting " + routeID2Update + " ShopData");
        if (_isDownloding)
        {
            yield break;
        }
        _isDownloding = true;

        StringBuilder sb = new StringBuilder();
        StringBuilder sbError = new StringBuilder();

        MonoHelper.Instance.InitWaiting("正在获取网络上走向图" + routeID2Update + "的数据");
        MonoHelper.Instance.AddWaiting();
        yield return CoroutineProxy.Instance.StartCoroutine(MonoHelper.Instance.RemoteGetRouteNetShopDataByPureID(routeID2Update));
        RoteAreaData raData = MonoHelper.Instance.GetRouteNetShopDataByPureID(routeID2Update);
        if (null == raData)
        {
            MonoHelper.Instance.HideLoading();
            var str = "网络问题或者服务器上不存在走向图" + routeID2Update + "的数据!(重新登录试试)";
            //Debug.LogError(str);
            WindowAlertDialog.ShowNewDlg(str, true);
            _isDownloding = false;
            yield break;
        }

        JDataShopConfig shopConfig;
        shopConfig = JDataShopConfig.LoadFromString(raData.StrConfig);
        if (null == shopConfig || !shopConfig.IsValid(routeID2Update))
        {
            MonoHelper.Instance.HideLoading();
            string fStr = "走向图" + routeID2Update + "商铺数据解析失败!";
            Debug.LogError(fStr);
            WindowAlertDialog.ShowNewDlg(fStr, true);
            _isDownloding = false;
            yield break;
        }

        string routeID = shopConfig.routeID;

        // backup local folder - all
        #region backup
        string orgPath = GetRouteFolderPath(routeID);
        sb.Clear();
        sb.Append(orgPath, "../", "backup/");
        sb.Append(routeID, "/", routeID, "_bak_", UtilsCommonS.Time2String(), "/");
        string backUpPath = sb.ToString();
        MonoHelper.Instance.InitWaiting("正在备份本地数据到" + backUpPath);
        DirectoryExtention.CloneDirectory(orgPath, backUpPath);
        #endregion

        var dicServerfileMap = shopConfig._dicPicName2Crc;
        if (null == dicServerfileMap || dicServerfileMap.Count == 0)
        {
            sbError.Append("走向图", routeID, "商铺没有商铺模板数据!\n");
            //WindowAlertDialog.ShowNewDlg("走向图" + routeID + "商铺没有商铺模板数据!", true);
        }

        string signFolerPath = GetSignFolderPath(routeID);
        var localFileInfos = DirectoryInfoExtention.GetDirFileInfosByExtSplit(signFolerPath, 
            SearchOption.TopDirectoryOnly, ShopEditor.All_FileExtend_shopSignPic);
        var dicLocalName2FileInfo = UtilsCommonS.FileInfos2Dic(localFileInfos);
        if (dicServerfileMap != null)
        {
            var it = dicServerfileMap.GetEnumerator();
            MonoHelper.Instance.SetWaitingMax(dicServerfileMap.Count);
            MonoHelper.Instance.InitWaiting("正在获取服务器商铺图片");
            while (it.MoveNext())
            {
                var item = it.Current;
                string serverName = item.Key;
                string serverCrc = item.Value;

                bool isRemoteGet = true;
                if (dicLocalName2FileInfo != null)
                {
                    FileInfo fInfo = dicLocalName2FileInfo.TryGetReturnValue(serverName);
                    if (fInfo != null)
                    {
                        string localCrc = fInfo.GetFileCrc();
                        if (!string.IsNullOrEmpty(localCrc))
                        {
                            if (localCrc.Equals(serverCrc))
                            {
                                isRemoteGet = false;
                            }
                        }
                    }
                }

                if (isRemoteGet)
                {
                    NameCrcData ncData = new NameCrcData(serverName, serverCrc);
                    ncData.AsyncRemoteGetData();
                    yield return ncData.WaitForResult();
                    if (ncData.IsRequestSuccess)
                    {
                        sb.Clear();
                        sb.Append(signFolerPath + serverName);
                        string signPicPath = sb.ToString();
                        UtilsCommonS.Save2File(signPicPath, ncData.GetDataBytes());
                    }
                    else
                    {
                        sbError.Append("\n文件", serverName, "下载失败", ncData.HttpResp_Error.WwwText);
                        //WindowAlertDialog.ShowNewDlg("文件" + serverName + "下载失败" + ncData.HttpResp_Error.WwwText, true);
                    }
                }

                MonoHelper.Instance.PopWaiting();
            }
        }

        string configFilePath = GetShopConfigFilePath(routeID);
        UtilsCommonS.Save2File(configFilePath, raData.StrConfig);

        string shopListFilePath = GetShopListFilePath(routeID);
        UtilsCommonS.Save2File(shopListFilePath, raData.StrShopList);

        string errStr = sbError.ToString();
        if (string.IsNullOrEmpty(errStr))
        {
            sb.Clear();
            sb.Append("走向图", routeID, "商铺数据下载完成, 请重新加载该走向图.");
            WindowAlertDialog.ShowNewDlg(sb.ToString());
        }
        else
        {
            sb.Clear();
            sb.Append("走向图", routeID, "商铺数据下载完成, 存在错误如下 : \n" + errStr);
            string str = sb.ToString();
            Debug.LogError(str);
            WindowAlertDialog.ShowNewDlg(str, true);
        }

        MonoHelper.Instance.HideLoading();
        _isDownloding = false;
    }

    public void OnKeyEvent()
    {
        if (!MonoHelper.IsFocusOnTextField())
            MoveShopModel();
    }
    void MoveShopModel()
    {
        Vector3 dir = Vector3.zero;
        Vector3 rot = Vector3.zero;
        Vector3 sca = Vector3.zero;
        if (!Input.GetKey(KeyCode.LeftAlt))
        {
            if (Input.GetKeyDown(KeyCode.UpArrow))
                dir += Vector3.forward;
            if (Input.GetKeyDown(KeyCode.DownArrow))
                dir += Vector3.back;
            if (Input.GetKeyDown(KeyCode.LeftArrow))
                dir += Vector3.right;
            if (Input.GetKeyDown(KeyCode.RightArrow))
                dir += Vector3.left;
            if (Input.GetKeyDown(KeyCode.R))
                dir += Vector3.up;
            if (Input.GetKeyDown(KeyCode.F))
                dir += Vector3.down;
            if (CurSelectShopModel != null && dir != Vector3.zero)
                CurSelectShopModel.Move(dir);

            if (Input.GetKeyDown(KeyCode.Q))
                rot += Vector3.down;
            if (Input.GetKeyDown(KeyCode.E))
                rot += Vector3.up;
            if (CurSelectShopModel != null && rot != Vector3.zero)
                CurSelectShopModel.Rotate(rot);
        }
        else
        {
            if (Input.GetKeyDown(KeyCode.UpArrow))
                sca += Vector3.down;
            if (Input.GetKeyDown(KeyCode.DownArrow))
                sca += Vector3.up;
            if (Input.GetKeyDown(KeyCode.LeftArrow))
                sca += Vector3.right;
            if (Input.GetKeyDown(KeyCode.RightArrow))
                sca += Vector3.left;
            if (CurSelectShopModel != null && sca != Vector3.zero)
                CurSelectShopModel.Scale(sca);
        }

        if (dir != Vector3.zero || rot != Vector3.zero || sca != Vector3.zero)
            onDataChange();

    }
}

public class JDataShopConfig : IJsonData
{
    const string StrPicNameCrc = "picNameCrc";
    public string routeID;
    public string shopNum;
    public string version;
    public JsonData data;

    public Dictionary<string, string> _dicPicName2Crc;

    public IJsonData ReadJsonData(JsonData jd)
    {
        routeID = jd.ReadString("routeID");
        shopNum = jd.ReadString("shopNum");
        version = jd.ReadString("version");
        data = jd["data"];
        JsonData picNameCrc = jd[StrPicNameCrc];
        if (picNameCrc != null)
        {
            _dicPicName2Crc = picNameCrc.ToItemVO<Dictionary<string, string>>();
        }

        return this;
    }

    public JsonData ToJsonData()
    {
        JsonData jd = new JsonData();
        jd["routeID"] = routeID;
        jd["shopNum"] = shopNum;
        jd["version"] = version;
        jd["data"] = data;
        if (_dicPicName2Crc != null)
        {
            jd[StrPicNameCrc] = _dicPicName2Crc.ToJsonData();
        }

        return jd;
    }

    public static JDataShopConfig LoadFromString(string str)
    {
        try
        {
            JsonData jd = JsonMapper.ToObject(str);
            JDataShopConfig newConfig = new JDataShopConfig();
            newConfig.ReadJsonData(jd);
            return newConfig;
        }
        catch (System.Exception ex)
        {
            Debug.LogError("解析Json失败!" + ex.Message);
            return null;	
        }
    }

    public bool IsValid(string validID, bool isNullSet = true)
    {
        if (string.IsNullOrEmpty(validID))
        {
            return !string.IsNullOrEmpty(routeID);
        }
        else
        {
            if (routeID != null && routeID != "null")
            {
                return routeID.Equals(validID);
            }
            else
            {
                if (isNullSet)
                {
                    routeID = validID;
                    return true;
                }
            }
        }

        return false;
    }
}